﻿using System;
using System.Threading;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// 线程扩展类
    /// </summary>
    public sealed class ThreadEx : IThreadEx
    {
        /// <summary>
        /// 线程要执行的委托
        /// </summary>
        private readonly Action<ThreadPara> _action = null;

        /// <summary>
        /// 线程名称
        /// </summary>
        private readonly string _name;
        /// <summary>
        /// 线程名称
        /// </summary>
        public string Name
        {
            get { return this._name; }
        }

        /// <summary>
        /// 是否后台运行[true:后台线程;false:前台线程]
        /// </summary>
        private readonly bool _isBackground;
        /// <summary>
        /// 是否后台运行[true:后台线程;false:前台线程]
        /// </summary>
        public bool IsBackground
        {
            get { return this._isBackground; }
        }

        private readonly object _data;
        /// <summary>
        /// 数据参数
        /// </summary>
        public object Data
        {
            get { return this._data; }
        }

        private readonly ThreadPriority? _priority;
        /// <summary>
        /// 线程优先级
        /// </summary>
        public ThreadPriority? Priority
        {
            get { return this._priority; }
        }

        /// <summary>
        /// 外部调用线程锁
        /// </summary>
        private readonly object _threadLock = new object();
        private bool _disposed = false;
        private ThreadItem _threadItem = null;




        /// <summary>
        /// 获取内部线程
        /// </summary>
        public Thread OwnerThread
        {
            get
            {
                lock (this._threadLock)
                {
                    if (this._threadItem == null)
                    {
                        return null;
                    }
                    else
                    {
                        return this._threadItem.OwnerThread;
                    }
                }
            }
        }

        /// <summary>
        /// 附加标记数据
        /// </summary>
        public object Tag { get; set; }




        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="action">线程要执行的委托</param>
        /// <param name="name">线程名称</param>
        /// <param name="isBackground">后台运行标识[true:后台线程;false:前台线程]</param>
        /// <param name="data">数据参数</param>
        /// <param name="priority">线程优先级</param>
        public ThreadEx(Action<ThreadPara> action, string name = null, bool isBackground = true, object data = null, ThreadPriority? priority = null)
        {
            this._name = name;
            this._isBackground = isBackground;
            this._data = data;
            this._priority = priority;
            this._action = action ?? throw new ArgumentNullException(nameof(action));
        }





        #region IThreadEx
        /// <summary>
        /// 线程执行完成事件
        /// </summary>
        public event EventHandler<ThreadExCompletedArgs> Completed;

        /// <summary>
        /// 触发线程执行完成事件
        /// </summary>
        /// <param name="type">线程执行完成类型</param>
        /// <param name="ex">当执行异常可取消时可能的异常信息</param>
        private void OnRaiseCompleted(ThreadExCompletedType type, Exception ex)
        {
            lock (this._threadLock)
            {
                if (this._threadItem != null)
                {
                    this.PrimitiveStop();
                }

                var handler = this.Completed;
                handler?.Invoke(this, new ThreadExCompletedArgs(type, ex));
            }
        }

        /// <summary>
        /// 获取线程当前的状态
        /// </summary>
        public ThreadState ThreadState
        {
            get
            {
                lock (this._threadLock)
                {
                    if (this._threadItem == null)
                    {
                        return System.Threading.ThreadState.Unstarted;
                    }
                    else
                    {
                        return this._threadItem.OwnerThread.ThreadState;
                    }
                }
            }
        }

        /// <summary>
        /// 获取当前托管线程的唯一标识符
        /// </summary>
        public int ManagedThreadId
        {
            get
            {
                lock (this._threadLock)
                {
                    if (this._threadItem == null)
                    {
                        throw new Exception("线程未启动");
                    }
                    else
                    {
                        return this._threadItem.OwnerThread.ManagedThreadId;
                    }
                }
            }
        }

        /// <summary>
        /// 当前线程是否正在运行
        /// </summary>
        public bool IsRuning
        {
            get
            {
                lock (this._threadLock)
                {
                    return this._threadItem != null;
                }
            }
        }

        /// <summary>
        /// 启动线程
        /// </summary>
        /// <param name="obj">线程启动参数</param>
        public void Start(object obj = null)
        {
            lock (this._threadLock)
            {
                if (this._disposed)
                {
                    throw new ObjectDisposedException(this.GetType().FullName);
                }

                if (this._threadItem != null)
                {
                    //ZLoger.Warn($"线程{this._name}已启动,不再重复启动.");
                    return;
                }

                this._threadItem = new ThreadItem(this, this._name, this._isBackground, obj, this._data, this._priority, this._action, this.OnRaiseCompleted);
                this._threadItem.Start();
            }
        }


        /// <summary>
        /// 停止线程
        /// </summary>
        public void Stop()
        {
            lock (this._threadLock)
            {
                if (this._disposed)
                {
                    throw new ObjectDisposedException(this.GetType().FullName);
                }

                if (this._threadItem != null)
                {
                    this.PrimitiveStop();
                }
                else
                {
                    //ZLoger.Warn($"线程{this._name}未启动,不作停止操作.");
                }
            }
        }

        private void PrimitiveStop()
        {
            this._threadItem.Stop();
            this._threadItem.Dispose();
            this._threadItem = null; ;
        }


        /// <summary>
        /// 停止线程
        /// </summary>
        /// <param name="timeoutMilliseconds">同步超时时间,-1表示无限期等待,单位/毫秒</param>
        /// <returns>如果线程已终止，则为 true；如果 false 参数指定的时间量已过之后还未终止线程，则为 timeout</returns>
        public bool SyncStop(int timeoutMilliseconds = -1)
        {
            bool result = true;
            lock (this._threadLock)
            {
                if (this._disposed)
                {
                    throw new ObjectDisposedException(this.GetType().FullName);
                }

                if (this._threadItem != null)
                {
                    result = this._threadItem.SyncStop(timeoutMilliseconds);
                    this._threadItem?.Dispose();
                    this._threadItem = null;
                }
            }
            return result;
        }
        #endregion

        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            try
            {
                lock (this._threadLock)
                {
                    if (this._disposed)
                    {
                        return;
                    }
                    this._disposed = true;

                    if (this._threadItem != null)
                    {
                        this.PrimitiveStop();
                    }
                }
            }
            catch (Exception ex)
            {
                ZLoger.Error(ex);
            }
        }





        #region 静态方法
        /// <summary>
        /// 创建线程对象
        /// </summary>
        /// <param name="action">线程要执行的委托</param>
        /// <param name="name">线程名称</param>
        /// <param name="isBackground">是否后台运行[true:后台线程;false:前台线程]</param>
        /// <param name="obj">线程启动参数</param>
        /// <returns>返回线程对象</returns>
        public static IThreadEx Start(Action<ThreadPara> action, string name = null, bool isBackground = true, object obj = null)
        {
            var thread = new ThreadEx(action, name, isBackground);
            thread.Start(obj);
            return thread;
        }

        /// <summary>
        /// 指定当前线程运行在指定CPU核心上
        /// </summary>
        /// <param name="coreIndex">指定CPU核心ID,从0开始[0-N]</param>
        public static void SetThreadRunCPUCore(int coreIndex)
        {
            OSSystemApis.SetCurrentThreadAffinityMask(coreIndex);
        }

        /// <summary>
        /// 指定hThread运行在核心dwThreadAffinityMask
        /// </summary>
        /// <param name="hThread">线程句柄</param>
        /// <param name="coreIndex">CPU核心编号</param>
        public static void SetThreadAffinityMask(IntPtr hThread, int coreIndex)
        {
            OSSystemApis.SetThreadAffinityMask(hThread, coreIndex);
        }

        /// <summary>
        /// 得到当前线程的句柄
        /// </summary>
        /// <returns>当前线程的句柄</returns>
        public static IntPtr GetCurrentThread()
        {
            return OSSystemApis.GetCurrentThread();
        }

        #endregion


    }

}
